const http = require("http");
const context = require("./context");
const request = require("./request");
const response = require("./response");
class Mykoa {
  constructor() {
    this.middlewares = [];
  }
  listen(...args) {
    // 创建服务器
    const server = http.createServer(async (req, res) => {
      // 创建上下文
      const ctx = this.createContext(req, res);
      // 组合中间件 获取的是 回调函数
      let fn = this.compose(this.middlewares);
      // 执行第一个中间件 并传入ctx
      await fn(ctx);
      // 响应 ctx.body 取得是response的body
      res.end(ctx.body);
    });
    // 启动服务器
    server.listen(...args);
  }
  // 因为ctx读取所以this指向ctx
  createContext(req, res) {
    // 创建上下文
    const ctx = Object.create(context);
    ctx.request = Object.create(request);
    ctx.response = Object.create(response);
    // 关联req和res 到上下文

    ctx.req = req;
    ctx.request.req = req;

    ctx.res = res;
    ctx.response.res = res;
    return ctx;
  }
  //
  compose(middlewares) {
    return (ctx) => {
      // 递归执行函数
      //访问了外部变量 middlewares 所以形成闭包 保存了 middleware 不被销毁
      // 又 因为next 访问了 i 所以形成闭包 保存了 i 不被销毁
      let dispatch = (i) => {
        let fn = middlewares[i]; // 获取当前函数
        // 如果函数不存在 返回一个成功的promise
        if (!fn) {
          return Promise.resolve();
        }
        // 定义next函数 用于递归执行下一个函数
        let next = () => {
          return dispatch(i + 1);
        };
        // 执行当前函数 并传入next函数
        return Promise.resolve(fn(ctx, next));
      };
      // 执行第一个函数
      return dispatch(0);
    };
  }
  use(middleware) {
    // 保存中间件
    this.middlewares.push(middleware);
  }
}

module.exports = Mykoa;
